package com.secsbrain.deploy.biz.impl;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;

import javax.annotation.Resource;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.secsbrain.cmdb.client.model.Server;
import com.secsbrain.deploy.biz.utils.HttpResponse;
import com.secsbrain.deploy.biz.IBuildRecordService;
import com.secsbrain.deploy.client.model.DeployParam;
import com.secsbrain.deploy.dal.mapper.BuildModelMapper;
import com.secsbrain.deploy.dal.model.BuildModel;
import com.secsbrain.deploy.dal.model.BuildRecord;
import com.secsbrain.deploy.utils.command.CommandRunner;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.secsbrain.deploy.utils.command.WriteToFileStrategy;
import com.secsbrain.cmdb.client.model.AppDetail;
import com.secsbrain.cmdb.client.model.SystemTypeEnums;
import com.secsbrain.deploy.biz.IBuildModelService;
import com.secsbrain.deploy.biz.utils.DeployUtils;
import com.secsbrain.deploy.biz.utils.JenkinsHttpUtils;
import com.alibaba.fastjson.JSON;
import com.baomidou.framework.service.impl.SuperServiceImpl;

/**
 * BuildModel 表数据服务层接口实现类
 */
@Service
public class BuildModelServiceImpl extends SuperServiceImpl<BuildModelMapper, BuildModel> implements IBuildModelService {

    private static final Logger logger = LoggerFactory.getLogger(BuildModelServiceImpl.class);

    public static final String OUT_OF_SERVICE_COMMAND = "/home/boot/out-of-service.sh";

    @Resource
    private CommandRunner commandRunner;

    @Value("${jenkins.url}")
    private String jenkinsUrl;

    @Value("${jenkins.userid}")
    private String userid;

    @Value("${jenkins.token}")
    private String token;

    @Value("${jenkins.k8s.url}")
    private String jenkinsK8sUrl;

    @Value("${jenkins.k8s.userid}")
    private String useridK8s;

    @Value("${jenkins.k8s.token}")
    private String tokenK8s;

    @Value("${command.run.server.hostname:}")
    private String saltServer;

    @Autowired
    private IBuildRecordService buildRecordService;

    /* (non-Javadoc)
     * @see IBuildModelService#createBuildModel(java.lang.String, DeployParam)
     */
    @Override
    @Transactional
    public void createBuildModel(String templateName, DeployParam deployParam, AppDetail appDetail) {
        BuildModel buildModelParam = new BuildModel();
        buildModelParam.setAppId(deployParam.getAppId());
        int count = this.selectCount(buildModelParam);

        //记录BuildModel，如果下面任一步骤失败，则需要人工干预
        BuildModel buildModel = new BuildModel();
        buildModel.setAppId(appDetail.getId());
        buildModel.setAppName(appDetail.getName());
        buildModel.setEnv(deployParam.getEnvName());
        buildModel.setSystemType(appDetail.getSystemType());
        buildModel.setCreateTime(new Date());
        buildModel.setModelJson(JSON.toJSONString(deployParam));
        this.insertSelective(buildModel);

        if (count > 0) {
            return;
        }

        if (deployParam.isSwitchflow()) {
//			if(SystemTypeEnums.DOTNET.toString().equals(appDetail.getSystemType())){
//				//调用切流nginx脚本
//				this.handleSwitchFlow(deployParam, appDetail);
//			}else
            if (SystemTypeEnums.SPRING_BOOT.toString().equals(appDetail.getSystemType())) {
                buildRecordService.getGroupServerIp(deployParam.getSwitchEnvName(), appDetail.getServerList());
            }
        }

        JenkinsHttpUtils jenkinsHttpUtils = null;
        if (deployParam.isK8sFlag()) {
            jenkinsHttpUtils = new JenkinsHttpUtils(jenkinsK8sUrl, useridK8s, tokenK8s);
        } else {
            jenkinsHttpUtils = new JenkinsHttpUtils(jenkinsUrl, userid, token);
        }

        //copy jenkins Job
        String jobName = deployParam.isK8sFlag() ? appDetail.getName() + "-" + Server.K8S_HOSTNAME : appDetail.getName();
        Map<String, String> params = new HashMap<>();
        params.put("name", jobName);
        params.put("mode", "copy");
        params.put("from", deployParam.isK8sFlag() ? templateName + "-" + Server.K8S_HOSTNAME : templateName);
        HttpResponse httpResponse = jenkinsHttpUtils.submitPost("/createItem", params);
        String createItemRes = httpResponse.getResult();
        if (createItemRes != null) {
            //如果不是空，说明失败了
            throw new RuntimeException(createItemRes);
        }

        InputStream configXml = jenkinsHttpUtils.geXmlInputStream("/job/" + jobName + "/config.xml");

        SAXReader reader = new SAXReader();
        try {
            Document document = reader.read(configXml);
            // 替换模板信息
            Element element = document.getRootElement();
            element.element("description").setText(appDetail.getDesc());//任务描述
            if (element.element("scm").element("userRemoteConfigs") != null) {
                element.element("scm").element("userRemoteConfigs").element("hudson.plugins.git.UserRemoteConfig")
                        .element("url").setText(appDetail.getGitUrl());
            }

            if (deployParam.isK8sFlag()) {
                this.replaceConfigParamK8s(deployParam, appDetail, element);
            } else {
                this.replaceConfigParam(deployParam, appDetail, element);
            }

            //更新job配置
            String configRes = jenkinsHttpUtils.submitPostXml("/job/" + jobName + "/config.xml", document.asXML());
            if (configRes != null) {
                throw new RuntimeException(configRes);
            }
            HttpResponse disableResponse = jenkinsHttpUtils.submitPost("/job/" + jobName + "/disable", null);
            String disableRes = disableResponse.getResult();
            if (disableRes != null) {
                throw new RuntimeException(disableRes);
            }
            HttpResponse enableResponse = jenkinsHttpUtils.submitPost("/job/" + jobName + "/enable", null);
            String enableRes = enableResponse.getResult();
            if (enableRes != null) {
                throw new RuntimeException(enableRes);
            }
        } catch (DocumentException e) {
            logger.error("xml解析异常", e);
            throw new RuntimeException("xml解析异常", e);
        }

    }

    /**
     * 功能描述: <br>
     * 获取Java脚本发布相关参数
     *
     * @param deployParam
     * @return
     */
    private String getDeployParams(DeployParam deployParam) {
        //deploy.sh root@10.0.0.99 cloud-console-service /opt/jar
        String targetPath = deployParam.getTargetPath();
        String jarName = targetPath.substring(targetPath.lastIndexOf("/") + 1, targetPath.lastIndexOf("."));
        return deployParam.getRemoteCmdPath() + " " + saltServer + " " + jarName + " " + deployParam.getRemoteFloder();
    }

    /**
     * 功能描述: <br>
     * 替换k8s配置参数
     *
     * @param deployParam
     * @param appDetail
     * @param element
     */
    @SuppressWarnings("unchecked")
    private void replaceConfigParamK8s(DeployParam deployParam, AppDetail appDetail, Element element) {
//		if(DeployUtils.isLinuxNec(appDetail.getSystemType())){
//	    	List<Element> list=element.element("postbuilders").elements("hudson.tasks.Shell");
//    		//目标文件位置
//    		Element deliverCommandElement=list.get(0).element("command");
//	    	String deliverCommand=deliverCommandElement.getText();
//	    	String[] deliverCommandArry=deliverCommand.split(" ");
//	    	deliverCommandElement.setText(deliverCommandArry[0]+" "+deployParam.getTargetPath());
//    	}
    }

    /**
     * 功能描述: <br>
     * 替换配置参数
     *
     * @param deployParam
     * @param appDetail
     * @param element
     */
    @SuppressWarnings("unchecked")
    private void replaceConfigParam(DeployParam deployParam, AppDetail appDetail, Element element) {
        if (DeployUtils.isLinuxNec(appDetail.getSystemType())) {
            List<Element> list = element.element("postbuilders").elements("hudson.tasks.Shell");
            if (list.size() > 2) {
                Element outOfServiceCommandElement = list.get(1).element("command");
                if (outOfServiceCommandElement.getText().startsWith(OUT_OF_SERVICE_COMMAND)) {
                    //中间有个下线服务的命令
                    //传送文件命令
                    Element deliverCommandElement = list.get(0).element("command");
                    String deliverCommand = deliverCommandElement.getText();
                    String[] deliverCommandArry = deliverCommand.split(" ");
                    deliverCommandElement.setText(deliverCommandArry[0] + " " + deployParam.getTargetPath() + " " + deployParam.getRemoteFloder());
                    //下线服务命令
                    if (deployParam.isSwitchflow()) {
                        String outOfServiceCommand = outOfServiceCommandElement.getText();
                        String[] outOfServiceCommandArry = outOfServiceCommand.split(" ");
                        outOfServiceCommandElement.setText(outOfServiceCommandArry[0] + " " + deployParam.getRegistCenterUrl() + " "
                                + deployParam.getApplicationName() + " " + deployParam.getPort() + " " + deployParam.getWaitTime());
                    }
                    //salt远程执行发布命令
                    Element deployCommandElement = list.get(2).element("command");
                    String deployCommand = deployCommandElement.getText();
                    String[] deployCommandArry = deployCommand.split(" ");
                    deployCommandElement.setText(deployCommandArry[0] + " " + this.getDeployParams(deployParam));

                    if (!deployParam.isSwitchflow()) {
                        list.remove(1);
                    }
                }
            } else {
                //传送文件命令
                Element deliverCommandElement = list.get(0).element("command");
                String deliverCommand = deliverCommandElement.getText();
                String[] deliverCommandArry = deliverCommand.split(" ");
                deliverCommandElement.setText(deliverCommandArry[0] + " " + deployParam.getTargetPath() + " " + deployParam.getRemoteFloder());

                //salt远程执行发布命令
                Element deployCommandElement = list.get(1).element("command");
                String deployCommand = deployCommandElement.getText();
                String[] deployCommandArry = deployCommand.split(" ");
                deployCommandElement.setText(deployCommandArry[0] + " " + this.getDeployParams(deployParam));

                //下线服务命令
                if (deployParam.isSwitchflow()) {
                    Element outOfServiceTask = (Element) list.get(0).clone();
                    Element outOfServiceCommandElement = outOfServiceTask.element("command");
                    outOfServiceCommandElement.setText(OUT_OF_SERVICE_COMMAND + " " + deployParam.getRegistCenterUrl() + " "
                            + deployParam.getApplicationName() + " " + deployParam.getPort() + " " + deployParam.getWaitTime());
                    list.add(1, outOfServiceTask);
                }

            }
        } else if (DeployUtils.isStaticNec(appDetail.getSystemType())) {
            List<Element> list = element.element("builders").elements("hudson.tasks.Shell");
            //编译命令
            Element buildCommandElement = list.get(1).element("command");
            String buildCommand = buildCommandElement.getText();
            String[] buildCommandArry = buildCommand.split(" ");
            buildCommandElement.setText(buildCommandArry[0] + " " + deployParam.getBuildCmd());

            //传送文件命令
            Element deliverCommandElement = list.get(2).element("command");
            String deliverCommand = deliverCommandElement.getText();
            String[] deliverCommandArry = deliverCommand.split(" ");
            deliverCommandElement.setText(deliverCommandArry[0] + " " + deployParam.getRemoteFloder());
        }
//		else if(SystemTypeEnums.DOTNET.toString().equals(appDetail.getSystemType())){
//    		List<Element> list=element.element("builders").elements("hudson.tasks.Shell");
//    		Element buildCommandElement=list.get(2).element("command");
//	    	String buildCommand=buildCommandElement.getText();
//	    	String[] buildCommandArry=buildCommand.split(" ");
//	    	buildCommandElement.setText(buildCommandArry[0]+" "+appDetail.getGitUrl());
//    	}
    }

    /**
     * 功能描述: <br>
     * 切流配置处理
     *
     * @param deployParam
     * @param appDetail
     */
    private void handleSwitchFlow(DeployParam deployParam, AppDetail appDetail) {
        Map<String, String> map = buildRecordService.getGroupServerIp(deployParam.getSwitchEnvName(), appDetail.getServerList());

        Map<String, String> params = new HashMap<>();
        params.put("appName", appDetail.getName());
        params.put("serverAIp", map.get("A"));
        params.put("serverBIp", map.get("B"));

        String command = "/opt/scripts/changeNginxUpstream.sh " + params.get("appName") +
                " " + params.get("serverAIp") + " " + params.get("serverBIp");
        WriteToFileStrategy writeToFileStrategy = new WriteToFileStrategy("/home/logs/changeNginxUpstream", command, deployParam.getAppId());
        try {
            commandRunner.exec(command, writeToFileStrategy);
        } catch (IOException e) {
            logger.error("", e);
            throw new RuntimeException(e);
        }

    }

    /* (non-Javadoc)
     * @see IBuildModelService#updateBuildModel(java.lang.String, DeployParam, com.secsbrain.cmdb.client.model.AppDetail)
     */
    @Override
    @Transactional
    public void updateBuildModel(DeployParam deployParam, AppDetail appDetail) {
        BuildModel buildModel = new BuildModel();
        buildModel.setAppId(appDetail.getId());
        buildModel.setAppName(appDetail.getName());
        buildModel.setSystemType(appDetail.getSystemType());
        buildModel.setCreateTime(new Date());
        buildModel.setModelJson(JSON.toJSONString(deployParam));

        BuildModel buildModelParam = new BuildModel();
        buildModelParam.setAppId(deployParam.getAppId());
        buildModelParam.setEnv(deployParam.getEnvName());
        this.updateSelective(buildModel, buildModelParam);

        if (deployParam.isSwitchflow()) {
//			if(SystemTypeEnums.DOTNET.toString().equals(appDetail.getSystemType())){
//				//调用切流nginx脚本
//				this.handleSwitchFlow(deployParam, appDetail);
//			}else
            if (SystemTypeEnums.SPRING_BOOT.toString().equals(appDetail.getSystemType())) {
                buildRecordService.getGroupServerIp(deployParam.getSwitchEnvName(), appDetail.getServerList());
            }
        }

        JenkinsHttpUtils jenkinsHttpUtils = null;
        if (deployParam.isK8sFlag()) {
            jenkinsHttpUtils = new JenkinsHttpUtils(jenkinsK8sUrl, useridK8s, tokenK8s);
        } else {
            jenkinsHttpUtils = new JenkinsHttpUtils(jenkinsUrl, userid, token);
        }

        String jobName = deployParam.isK8sFlag() ? appDetail.getName() + "-" + Server.K8S_HOSTNAME : appDetail.getName();
        InputStream configXml = jenkinsHttpUtils.geXmlInputStream("/job/" + jobName + "/config.xml");

        SAXReader reader = new SAXReader();
        try {
            Document document = reader.read(configXml);
            // 替换模板信息
            Element element = document.getRootElement();
            element.element("description").setText(appDetail.getDesc());//任务描述
            if (element.element("scm").element("userRemoteConfigs") != null) {
                element.element("scm").element("userRemoteConfigs").element("hudson.plugins.git.UserRemoteConfig")
                        .element("url").setText(appDetail.getGitUrl());
            }

            if (deployParam.isK8sFlag()) {
                this.replaceConfigParamK8s(deployParam, appDetail, element);
            } else {
                this.replaceConfigParam(deployParam, appDetail, element);
            }

            //更新job配置
            String configRes = jenkinsHttpUtils.submitPostXml("/job/" + jobName + "/config.xml", document.asXML());
            if (configRes != null) {
                throw new RuntimeException(configRes);
            }
        } catch (DocumentException e) {
            logger.error("xml解析异常", e);
            throw new RuntimeException("xml解析异常", e);
        }
    }

    /* (non-Javadoc)
     * @see IBuildModelService#deleteBuildModel(com.secsbrain.cmdb.client.model.AppDetail)
     */
    @Override
    @Transactional
    public void deleteBuildModel(Long buildModelId, String envName, AppDetail appDetail) {
        this.deleteById(buildModelId);

        BuildRecord buildRecordUp = new BuildRecord();
        buildRecordUp.setDelStatus(1);

        BuildRecord buildRecordWhere = new BuildRecord();
        buildRecordWhere.setAppId(appDetail.getId());
        buildRecordWhere.setEnv(envName);
        buildRecordService.updateSelective(buildRecordUp, buildRecordWhere);

        boolean k8s = false;//TODO 待改
        JenkinsHttpUtils jenkinsHttpUtils = null;
        if (k8s) {
            jenkinsHttpUtils = new JenkinsHttpUtils(jenkinsK8sUrl, useridK8s, tokenK8s);
        } else {
            jenkinsHttpUtils = new JenkinsHttpUtils(jenkinsUrl, userid, token);
        }
        HttpResponse httpResponse = jenkinsHttpUtils.submitPost("/job/" + appDetail.getName() + "/doDelete", null);
        String delRes = httpResponse.getResult();
        if (delRes != null) {
            throw new RuntimeException(delRes);
        }
    }

    @Override
    public List<String> fetchBranch(String jobName,boolean k8sFlag) {
        JenkinsHttpUtils jenkinsHttpUtils = null;
        if (k8sFlag) {
            jenkinsHttpUtils = new JenkinsHttpUtils(jenkinsK8sUrl, useridK8s, tokenK8s);
        } else {
            jenkinsHttpUtils = new JenkinsHttpUtils(jenkinsUrl, userid, token);
        }

        HttpResponse httpResponse = jenkinsHttpUtils.submitPost("/job/" + jobName + "/descriptorByName/net.uaznia.lukanus.hudson.plugins.gitparameter.GitParameterDefinition/fillValueItems?param=branch", null);
        String result=httpResponse.getResult();
        JSONObject jsonObject = JSON.parseObject(result);
        JSONArray jsonArray = jsonObject.getJSONArray("values");
        List<String> branchList=new ArrayList<>();
        for(int i=0;i<jsonArray.size();i++){
            branchList.add(jsonArray.getJSONObject(i).getString("value"));
        }
        return branchList;
    }

}